#include "stdafx.h"
#include "Tunnel.h"

#include "Filesystem.h"

Tunnel::Tunnel(Cvekas::RendererPtr renderer, Cvekas::VectorBatchPtr vector_batch)
: renderer(renderer), vector_batch(vector_batch),
  camera(Vector3(0.0f, 0.0f, -28.0f), Vector3(0.0f, 0.0f, 1.0f), Vector3(0.0f, 1.0f, 0.0f))
{
}

Tunnel::~Tunnel()
{
}

void Tunnel::init(boost::weak_ptr<Demo> owner)
{
	this->owner = owner;

	MeshPtr tunnel_mesh = MeshPtr(new Mesh(Filesystem::redirect("Tunnel.cmf")));
	EffectPtr tunnel_effect = video_device->getEffectManager()->load("Tunnel", Filesystem::redirect("Tunnel.fx"));
	tunnel_effect->getAutoParams()->addDynamic("light1_pos", &light_pos[0]);
	tunnel_effect->getAutoParams()->addDynamic("light2_pos", &light_pos[1]);
	tunnel_effect->getAutoParams()->addDynamic("light3_pos", &light_pos[2]);
	tunnel_effect->getAutoParams()->addDynamic("light_attenuations", &light_attenuations);

	tunnel = RenderableMeshPtr(new RenderableMesh(tunnel_mesh, tunnel_effect, EffectParamsPtr(), 0));

	MeshPtr light_mesh = MeshPtr(new Mesh(Filesystem::redirect("Light.cmf")));
	EffectPtr light_effect = video_device->getEffectManager()->load("Light", Filesystem::redirect("Light.fx"));
	
	EffectParamsPtr light1_params = EffectParamsPtr(new EffectParams(light_effect.get()));
	light1_params->add("light_color", Vector3(0.8f, 0.1f, 0.1f));
	EffectParamsPtr light2_params = EffectParamsPtr(new EffectParams(light_effect.get()));
	light2_params->add("light_color", Vector3(0.1f, 0.8f, 0.1f));
	EffectParamsPtr light3_params = EffectParamsPtr(new EffectParams(light_effect.get()));
	light3_params->add("light_color", Vector3(0.1f, 0.1f, 0.8f));

	for(uint i = 0; i < trail_length; ++i)
	{
		light1[i] = RenderableMeshPtr(new RenderableMesh(light_mesh, light_effect, light1_params, 1));
		light2[i] = RenderableMeshPtr(new RenderableMesh(light_mesh, light_effect, light2_params, 1));
		light3[i] = RenderableMeshPtr(new RenderableMesh(light_mesh, light_effect, light3_params, 1));

		//float scale = smoothstep(0.1f, 0.02f, (float)i/(float)trail_length);
		//light1[i]->setScale(Vector3(scale, scale, scale));
		//light2[i]->setScale(Vector3(scale, scale, scale));
		//light3[i]->setScale(Vector3(scale, scale, scale));
	}

	light_pos[0] = Vector3(0.0f, 0.0f, 25.0f);
	light_pos[1] = Vector3(0.0f, 0.0f, 0.0f);
	light_pos[2] = Vector3(0.0f, 0.0f, -25.0f);
	light_attenuations = Vector3(1.0f, 1.0f, 1.0f);

	fullscreen_rect.push_back(Vector2(0.0f, 0.0f));
	fullscreen_rect.push_back(Vector2(1024.0f, 0.0f));
	fullscreen_rect.push_back(Vector2(1024.0f, 576.0f));
	fullscreen_rect.push_back(Vector2(0.0f, 576.0f));
}

void Tunnel::close()
{
}

void lightSize(float t, float dt, float& l1, float& l2, float& l3)
{
	l1 = smoothstep(0.0f, 0.1f, transformT(40.3f, 41.3f, t));
	l2 = smoothstep(0.0f, 0.1f, transformT(42.3f, 43.3f, t));
	l3 = smoothstep(0.0f, 0.1f, transformT(44.3f, 45.3f, t));

	l1 = smoothstep(l1, l1/5.0f, dt * 4.0f);
	l2 = smoothstep(l2, l2/5.0f, dt * 4.0f);
	l3 = smoothstep(l3, l3/5.0f, dt * 4.0f);
}

void moveLights(float t, float lights_z, Vector3& light1_pos, Vector3& light2_pos, Vector3& light3_pos)
{
	light1_pos = Vector3(2.1f * sin(t) * cos(t/1.9f), 2.1f * cos(t/1.2f) * cos(t/1.5f), lights_z + sin(t/1.3f) * 3.0f); 
	light2_pos = Vector3(1.8f * cos(t/1.11f) * sin(t/1.2f), 1.8f * sin(t*1.5f) * cos(t/1.4f), lights_z + cos(t/1.4f) * 2.8f);
	light3_pos = Vector3(2.1f * sin(t/1.4f+0.3f) * sin(t/1.8f), 2.1f * cos(t/1.6f) * sin(t/1.9f), lights_z + sin(t/1.8f + 0.2f) * 3.1f);
}

void Tunnel::update(float t)
{
	if(t < 40.5f)
	{
		float alpha = lerp(1.0f, 0.0f, transformT(40.2f, 40.5f, t));
		Color c(255, 255, 255, (int)(alpha * 255.0f));
		vector_batch->drawPolygon(2, fullscreen_rect, c);
	}
	if(t > 72.0f)
	{
		float alpha = lerp(0.0f, 1.0f, transformT(72.0f, 74.0f, t));
		Color c(0, 0, 0, (int)(alpha * 255.0f));
		vector_batch->drawPolygon(2, fullscreen_rect, c);
	}
	light_attenuations.x = smoothstep(1.0f, 0.1f, transformT(40.3f, 41.3f, t));
	light_attenuations.y = smoothstep(1.0f, 0.1f, transformT(42.3f, 43.3f, t));
	light_attenuations.z = smoothstep(1.0f, 0.1f, transformT(44.3f, 45.3f, t));

	float camera_z = lerp(-50.0f, 10.0f, transformT(40.3f, 65.0f, t));
	float lights_z = lerp(-44.0f, 16.0f, transformT(40.3f, 65.0f, t));
	float tz = transformT(70.0f, 73.0f, t);
	tz = tz < 0.0f ? 0.0f : tz;
	lights_z = smoothstep(lights_z, lights_z + 25.0f, tz*tz);
	moveLights(t, lights_z, light_pos[0], light_pos[1], light_pos[2]);	

	for(uint i = 0; i < trail_length; ++i)
	{
		Vector3 l1, l2, l3;
		float dt = lerp(0.0f, 0.25f, (float)i/(float)trail_length);
		float lights_z = lerp(-44.0f, 16.0f, transformT(40.3f, 65.0f, t-dt));
		
		float tz = transformT(70.0f, 73.0f, t-dt);
		tz = tz < 0.0f ? 0.0f : tz;
		lights_z = smoothstep(lights_z, lights_z + 25.0f, tz*tz);
		moveLights(t-dt, lights_z, l1, l2, l3);
		light1[i]->setPosition(l1);
		light2[i]->setPosition(l2);
		light3[i]->setPosition(l3);

		float s1, s2, s3;
		lightSize(t, dt, s1, s2, s3);
		light1[i]->setScale(Vector3(s1, s1, s1));
		light2[i]->setScale(Vector3(s2, s2, s2));
		light3[i]->setScale(Vector3(s3, s3, s3));
	}

	Vector3 camera_pos((sin(t/1.1f)+cos(t/1.2f))*0.7f, cos(t/1.3f)*cos(t/1.4f)*0.7f, camera_z);
	camera.setPosition(camera_pos);
	Vector3 camera_target(0.0f, 0.0f, camera_z + 5.0f);
	camera.setDirection(camera_target - camera_pos);
}

void Tunnel::render(float t)
{
	//light1->setPosition(light_pos[0]);
	//light2->setPosition(light_pos[1]);
	//light3->setPosition(light_pos[2]);

	video_device->setClearColor(Color(0, 0, 0));
	video_device->getRenderingParams().setCamera(camera);

	video_device->beginScene();
	renderer->prepare(*tunnel);
	for(uint i = 0; i < trail_length; ++i)
	{
		renderer->prepare(*(light1[i]));
		renderer->prepare(*(light2[i]));
		renderer->prepare(*(light3[i]));
	}
	vector_batch->present();
	renderer->render();
	video_device->endScene();

	renderer->endFrame();
}